"""
Created on 06-Oct-2009

@author: dexen
"""

import os
import sys
import cPickle
import sqlite3
import inspect

import dexen
from dexen.system import util
from dexen.system.base import task as taskbase

#===============================================================================
# GLOBALS
#===============================================================================
db_file = os.path.join(os.path.dirname(__file__), "database", "dexen.db")
print db_file

sqlite3.register_adapter(list, cPickle.dumps)
sqlite3.register_converter("pickle", cPickle.loads)
sqlite3.register_converter("binstr", str)

class SchemaManager(object):
    def __init__(self):
        self._create_connection()
        self._create_schema_table()
        
    def _create_schema_table(self):
        c = self.conn.cursor()
        if not self._has_schema_table():
            c.execute("""
                create table schema(
                    id integer primary key autoincrement, 
                    name,
                    content binstr, 
                    tasks pickle)""")

    def _create_connection(self):
        self.conn = sqlite3.connect(db_file, detect_types=sqlite3.PARSE_DECLTYPES)
        self.conn.text_factory = sqlite3.OptimizedUnicode
        self.conn.row_factory = sqlite3.Row
        
    def refresh_tables(self):
        if self._has_schema_table():
            c = self.conn.cursor()
            c.execute("drop table schema")
            self._create_schema_table()
            
    def _has_schema_table(self):
        c = self.conn.cursor()
        c.execute("select name from sqlite_master where name=?", ("schema",))
        return c.fetchone() != None
        
    def has_schema(self, schema_name):
        c = self.conn.cursor()
        c.execute("select name from schema where name=?", (schema_name,))
        return c.fetchone() != None

    def _insert_schema(self, schema_name, schema_zip, tasks):
        c = self.conn.cursor()
        entry = (schema_name, sqlite3.Binary(schema_zip), tasks)
        c.execute("insert into schema values (null,?,?,?)", entry)
        self.conn.commit()
    
    def _extract_tasknames(self, modulename):
        """
        
        Returns list of tasks found in the module.
        The task is a dict type composed of modulename, classname, tasktype 
        
        """
        module = __import__(modulename, fromlist=[""])
        members = inspect.getmembers(module)
        tasks = []
        for member in members:
            if inspect.isclass(member[1]):
                task=taskbase.TaskInfo()
                task.modulename = modulename
                task.classname = member[0]
                task.name = "%s.%s" %(task.modulename, task.classname)
                if issubclass(member[1], dexen.Task):
                    task.type = taskbase.NonInitType
                    tasks.append(task)
                if issubclass(member[1], dexen.InitTask):
                    task.type = taskbase.InitType
                    tasks.append(task)
        return tasks
        
    def _extract_tasks(self, schema_zip):
        tasks = []
        output_dir = "temp"
        util.unzip(schema_zip, output_dir)
        cur_dir = os.getcwd()
        sys.path.append(os.path.abspath(output_dir))
        os.chdir(output_dir)
        for root, dirs, files in os.walk("tasks"):
            for file in files:
                if file.endswith(".py"):
                    modulename = os.path.join(root, file[:-3])
                    assert isinstance(modulename, str)
                    modulename = modulename.replace("/", ".")
                    tasks.extend(self._extract_tasknames(modulename))
        os.chdir(cur_dir)
        sys.path = sys.path[:-1]
        return tasks
        
    def set_schema(self, schema_name, schema_zip):
        if self.has_schema(schema_name):
            raise Exception("schema name already exists in the database")
        tasks = self._extract_tasks(schema_zip)
        #for task in tasks:
        #    print task
        self._insert_schema(schema_name, schema_zip, tasks)
    
    def get_schema(self, schema_name):
        c = self.conn.cursor()
        c.execute("select * from schema where name=?", (schema_name,))
        result = c.fetchall()
        assert len(result) == 1
        return result[0]
    
    def get_schema_names(self):
        c = self.conn.cursor()
        c.execute("select name from schema")
        result = c.fetchall()
        result = [item[0] for item in result]
        print "get schema names results\n", result
        return result
        
    def get_schema_content(self, schema_name):
        schema = self.get_schema(schema_name)
        assert schema["name"] == schema_name
        return schema["content"]
    
    def get_schema_tasks(self, schema_name):
        schema = self.get_schema(schema_name)
        tasks = schema["tasks"]
        return tasks
    
    def delete_schema(self, schema_name):
        c = self.conn.cursor()
        if self.has_schema(schema_name):
            c.execute("delete from schema where name=?", (schema_name,))
            self.conn.commit()

    def num_schemas(self):
        c = self.conn.cursor()
        c.execute("select name from schema")
        return len(c.fetchall())

def test1():
    from dexen.system import constants    
    schema_mgr = SchemaManager()
    schema_mgr.refresh_tables()
    schema_dir = os.path.join(constants.SCHEMAS_DIR, "packing_boxes_v1")
    schema_zip = util.get_schema_zip(schema_dir)
    schema_len = len(schema_zip)
    print type(schema_zip)
    print schema_len
    schema_mgr.set_schema("pb1", schema_zip)
    assert schema_mgr.has_schema("pb1")
    schema = schema_mgr.get_schema("pb1")
    assert schema["name"] == "pb1"
    assert schema["content"] == schema_zip
    print "content type", type(schema["content"])
    
    """
    f = open("derdest.zip", "wb")
    f.write(schema["content"])
    f.close()
    """
    tasks = schema_mgr.get_schema_tasks("pb1")
    for task in tasks:
        print task

def test2():
    from dexen.system import constants
    schema_mgr = SchemaManager()
    schema_mgr.refresh_tables()
    schema_dir = os.path.join(constants.SCHEMAS_DIR, "packing_boxes_v1")
    schema_zip = util.get_schema_zip(schema_dir)
    schema_mgr.set_schema("pb1", schema_zip)
    assert schema_mgr.has_schema("pb1")
    assert schema_mgr.num_schemas() == 1

    schema_mgr.get_schema_names()

    schema_mgr.delete_schema("pb1")
    assert schema_mgr.num_schemas() == 0
    assert not schema_mgr.has_schema("pb1")
    
def test_suite():
    #test1()
    test2()
    
if __name__ == "__main__":
    test_suite()